package main

import (
	"bytes"
	"fmt"
	"os"
	"path"
	"sync"
	"time"
	"strconv"
)

type M3U8 struct {
	Gid       string
	Seq       int
	Heartbeat int64
	Base_url  string
	Start     time.Time
}

var Cached map[string]M3U8
var lock sync.RWMutex

const (
	CLIENTS   = 50000
	HOWMANYTS = 3
)

func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func walkDir(gid string, start time.Time) ([]string, time.Time) {
	i := 0
	j := 0
	var which time.Time
	files := make([]string, 0, 4)
	for i < 4 {
		//filename := start.Format("live-2006-01-02_15-04-05.ts")
                st := strconv.FormatInt(start.Unix(), 10)
		filename := st + ".ts"
		ok, _ := PathExists(path.Join(gid, filename))
		if ok {
                        j = 0
                        i += 1
                        if i == 2 {
                            which = start
                        }
			files = append(files, filename)
			start = start.Add(time.Second * 8)
		       //fmt.Println(filename)
		} else {
			start = start.Add(time.Second * 1)
			j += 1
			if j > 60 {
                            logger.Println("Miss TS File")
                            //check the future ts files
                            which = start
			    break
			}
		}
	}

	return files, which
}

func (p *M3U8) List() []string {
	files, start := walkDir(p.Gid, p.Start)
	p.Start = start
	return files
}

func (p *M3U8) genM3u8(files []string) []byte {

	M3U8_HEADER := "#EXTM3U\n#EXT-X-VERSION:2\n#EXT-X-ALLOW-CACHE:YES\n#EXT-X-MEDIA-SEQUENCE:"
	M3U8_DURATION := "#EXT-X-TARGETDURATION:10"
	M3U8_ITEM := "\n#EXTINF:10,\n"
	//M3U8_END := "\n#EXT-X-ENDLIST"

	var buf bytes.Buffer
	tmp := fmt.Sprintf("%s%d\n%s", M3U8_HEADER, p.Seq, M3U8_DURATION)
	buf.WriteString(tmp)
	for _, v := range files {
		buf.WriteString(M3U8_ITEM)
		file := p.Base_url + path.Join(p.Gid, v)
		buf.WriteString(file)
	}
	//buf.WriteString(M3U8_END)
	return buf.Bytes()
}

func TimeshiftInit() {
	Cached = make(map[string]M3U8, CLIENTS)
	go Cleanup()
}
func Cleanup() {
	for {
		now := time.Now().Unix()
		lock.Lock()
		for k, v := range Cached {
			//client should query timeshift m3u8 in 10 seconds
			if now > (v.Heartbeat + 60) {
				fmt.Println("cleanup")
				delete(Cached, k)
			}
		}
		lock.Unlock()
		time.Sleep(60 * time.Second)
	}
}

func GetM3u8(gid string, start int64, uuid string, BASE_URL string) []byte {
	var buffer []byte
	lock.RLock()
	v, ok := Cached[uuid]
	lock.RUnlock()
	if !ok {

		m := M3U8{Gid: gid, Seq: 0, Heartbeat: time.Now().Unix(), Base_url: BASE_URL,
			Start: time.Unix(start, 0)}
		//fmt.Printf("%+v\n", m)
		files := m.List()
		if len(files) >= HOWMANYTS {
			buffer = m.genM3u8(files)
			m.Seq += 1
		}

		lock.Lock()
		Cached[uuid] = m
		lock.Unlock()

	} else {
		//fmt.Println(v, files)
		v.Heartbeat = time.Now().Unix()
		files := v.List()
		if len(files) >= HOWMANYTS {
			buffer = v.genM3u8(files)
			v.Seq += 1
		}

		lock.Lock()
		Cached[uuid] = v
		lock.Unlock()
	}
	return buffer
}
/*
func main() {
	TimeshiftInit()
	//os.Chdir("/data")

	t := time.Now()
	walkDir("hls", time.Unix(1615021411, 0))
	fmt.Println(time.Since(t))
        c:=GetM3u8("hls", 1615021411, "abc", "")
	fmt.Println(string(c))
        c=GetM3u8("hls", 1615021411, "abc", "")
	fmt.Println(string(c))
}*/
